/**
 * @module vim-loader
 */

import { G3d, MeshSection, G3dScene } from 'vim-format'
import { G3dMeshOffsets, G3dMeshCounts } from './g3dOffsets'


/**
 * 
 * 指定索引模型的集合,可以称之为g3d的子集
 * 可以进一步过滤或获取构建场景所需的偏移。
 */
export class G3dSubset {

  /**
   * 所有有效模型的索引
   * 实际上储存的是g3d的meshSubmesh数组索引
   */
  private _instances: number[]

  /**
   * 主要mesh索引
   * 非重复值列表
   */
  private _meshes: Array<number> = []
  /**
   * 上面数组的映射
   * 该数组表示上面数组有多少个instanceMesh可以设置
   * 
   */
  private _meshInstances: Array<Array<number>>

  /**
   * @param source 指定的集合源
   * @param instances 需要过滤的子集索引
   */
  constructor(
    private g3d: G3dScene | G3d,
    instances?: number[]
  ) {

    if (!instances) {
      instances = new Array<number>()
      for (let index = 0, length = g3d.instanceMeshes.length; index < length; index++) {
        const targetIndex = g3d.instanceMeshes[index]
        // 如果目标mesh索引有效,则储存
        if (targetIndex >= 0) {
          instances.push(index)
        }
      }
    }
    this._instances = instances
    console.log(instances);

    const map = new Map<number, Array<number>>()
    for (const index of instances) {
      const submeshArrIndex = g3d.instanceMeshes[index]
      if (!map.has(submeshArrIndex)) {
        this._meshes.push(submeshArrIndex)
        map.set(submeshArrIndex, [index])
      } else {
        map.get(submeshArrIndex)?.push(index)
      }
    }
    
    const meshLength = this._meshes.length
    this._meshInstances = new Array<Array<number>>(meshLength)
    for (let i = 0; i < meshLength; i++) {
      this._meshInstances[i] = map.get(this._meshes[i])!
    }
  }

  /**
   * 返回该子集的实例数量
   */
  get instanceCount() {
    return this._instances.length
  }

  /**
   * 通过subset的实例索引,给出g3d真实索引
   * @param subsetIndex 
   * @returns 
   */
  getG3dInstanceIndex(subsetIndex: number) {
    return this._instances[subsetIndex]
  }


  /**
   * 根据g3d mesh编号索引,返回subset的索引
   * @param index subset-based mesh index
   */
  getSourceMesh(index: number) {
    return this._meshes[index]
  }

  /**
   * 给出mesh的数量
   */
  get meshCount() {
    return this._meshes.length
  }

  /**
   * 给出指定mesh的索引统计数量
   * @param mesh subset-based mesh index
   * @param section sections to include based on opacity
   */
  getMeshIndexCount(meshIndex: number, section: MeshSection) {
    // mesh的indexMesh数量
    const instances = this.getMeshInstanceCount(meshIndex)
    // 指定mesh的索引数量
    const indices = this.g3d.getMeshIndexCount(
      this.getSourceMesh(meshIndex),
      section
    )
    return indices * instances
  }

  /**
   * Returns total vertex count for given mesh and section.
   * @param mesh subset-based mesh index
   * @param section sections to include based on opacity
   */
  getMeshVertexCount(mesh: number, section: MeshSection) {
    const instances = this.getMeshInstanceCount(mesh)
    const vertices = this.g3d.getMeshVertexCount(
      this.getSourceMesh(mesh),
      section
    )
    return vertices * instances
  }

  /**
   * 给出指定mesh的instanceMesh数量
   */
  getMeshInstanceCount(meshIndex: number) {
    return this._meshInstances[meshIndex].length
  }

  /**
   * 给出指定mesh的instanceMesh索引列表
   */
  getMeshInstances(mesh: number) {
    return this._meshInstances[mesh]
  }

  /**
   * 给出指定mesh的指定instance索引
   */
  getMeshInstance(mesh: number, index: number) {
    return this._meshInstances[mesh][index]
  }

  /**
   * 返回只有唯一实例的mesh索引列表
   */
  get singleInstance() {
    return this.filterByCount((count) => count === 1)
  }

  /**
   * 返回含有多个实例的mesh索引列表
   * 用于使用instancedMesh创建实例
   */
  get multipleInstances() {
    return this.filterByCount((count) => count > 1)
  }

  private filterByCount(predicate: (i: number) => boolean) {
    const set = new Set<number>()
    this._meshInstances.forEach((instances, i) => {
      if (predicate(instances.length)) {
        set.add(this._meshes[i])
      }
    })
    const instances = this._instances.filter((instance) => {
      return set.has(this.g3d.instanceMeshes[instance])
    })
   
    
    return new G3dSubset(this.g3d, instances)
  }

  /**
   * 工厂函数
   * 返回透明或不透明部分的几何体偏移集合
   */
  getOffsets(section: MeshSection) {
    return new G3dMeshOffsets(this, section)
  }

  /**
   * Returns the count of each mesh attribute.
   * 给出当前子集的属性统计
   */
  getAttributeCounts(section: MeshSection = 'all') {
    const result = new G3dMeshCounts()
    const count = this.meshCount
    result.meshes = count
    result.instances=this._instances.length
    for (let i = 0; i < count; i++) {
      result.indices += this.getMeshIndexCount(i, section)
      result.vertices += this.getMeshVertexCount(i, section)
    }

    return result
  }


  /**
   * 排除fliter中指定类型的object3d
   */
  except(obj3dIndexs: Set<number>) {
    const instances = this.filterOnArray(
      obj3dIndexs,
      false
    )
    return new G3dSubset(this.g3d, instances)
  }

  /**
   * 筛选出fliter中指定类型的object3d
   */
  filter(obj3dIndexs: Set<number>) {
    const instances = this.filterOnArray(
      obj3dIndexs,
      true
    )
    return new G3dSubset(this.g3d, instances)
  }



  private filterOnArray(
    set: Set<number>,
    has: boolean = true
  ) {
    const result = new Array<number>()
    for (const v of this._instances) {
      if (set.has(v) === has && this.g3d.instanceMeshes[v] >= 0) {
        result.push(v)
      }
    }
    return result
  }
}
